﻿using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PDFfromHTML
{
    class Program
    {
        static void Main(string[] args)
        {
            CreateOrderDetailPDF("<html><head><title>BooM</title></head><body>Boovendan M</body></html>", null, @"Sample.pdf");
        }

        /// <summary>
        /// Create the Order Detail PDF with the Lab Req/Result merged.
        /// </summary>
        /// <param name="HTMLContent"></param>
        /// <param name="ReqPDFFilePath"></param>
        /// <param name="PDFFilePath"></param>
        private static void CreateOrderDetailPDF(String HTMLContent, String MergePDFFilePath, String PDFFilePath)
        {
            MemoryStream msOutput = new MemoryStream();
            TextReader reader = new StringReader(HTMLContent);

            // step 1: creation of a document-object
            Document document = new Document(PageSize.A4, 30, 30, 30, 30);

            // step 2:
            // we create a writer that listens to the document
            // and directs a XML-stream to a file
            PdfWriter writer = PdfWriter.GetInstance(document, msOutput);

            // step 3: we create a worker parse the document
            HTMLWorker worker = new HTMLWorker(document);

            // step 4: we open document and start the worker on the document
            document.Open();
            worker.StartDocument();

            //Draw line for Formating the document.
            PdfContentByte cb = writer.DirectContent;
            cb.MoveTo(30, document.PageSize.Height - 53);
            cb.LineTo(document.PageSize.Width - 30, document.PageSize.Height - 53);
            cb.Stroke();
            cb.MoveTo(30, document.PageSize.Height - 90);
            cb.LineTo(document.PageSize.Width - 30, document.PageSize.Height - 90);
            cb.Stroke();

            // step 5: parse the html into the document
            worker.Parse(reader);

            // step 6: close the document and the worker
            worker.EndDocument();
            worker.Close();
            document.Close();
            if (String.IsNullOrEmpty(MergePDFFilePath))
            {
                File.WriteAllBytes(PDFFilePath, msOutput.ToArray());
            }
            else
            {
                byte[] bytes = System.IO.File.ReadAllBytes(MergePDFFilePath);
                Byte[] bytesPDFContent = MergeFiles(new List<Byte[]>() { msOutput.ToArray(), bytes });
                File.WriteAllBytes(PDFFilePath, bytesPDFContent);
            }
        }

        /// <summary>
        /// To Merge two PDF File Contents.
        /// </summary>
        /// <param name="sourceFiles"></param>
        /// <returns></returns>
        private static byte[] MergeFiles(List<byte[]> sourceFiles)
        {
            Document document = new Document();
            MemoryStream output = new MemoryStream();

            try
            {
                // Initialize pdf writer
                PdfWriter writer = PdfWriter.GetInstance(document, output);
                writer.PageEvent = new PdfPageEvents();

                // Open document to write
                document.Open();
                PdfContentByte content = writer.DirectContent;

                // Iterate through all pdf documents
                for (int fileCounter = 0; fileCounter < sourceFiles.Count; fileCounter++)
                {
                    // Create pdf reader
                    PdfReader reader = new PdfReader(sourceFiles[fileCounter]);
                    int numberOfPages = reader.NumberOfPages;

                    // Iterate through all pages
                    for (int currentPageIndex = 1; currentPageIndex <=
                                       numberOfPages; currentPageIndex++)
                    {
                        // Determine page size for the current page
                        document.SetPageSize(
                           reader.GetPageSizeWithRotation(currentPageIndex));

                        // Create page
                        document.NewPage();
                        PdfImportedPage importedPage =
                          writer.GetImportedPage(reader, currentPageIndex);


                        // Determine page orientation
                        int pageOrientation = reader.GetPageRotation(currentPageIndex);
                        if ((pageOrientation == 90) || (pageOrientation == 270))
                        {
                            content.AddTemplate(importedPage, 0, -1f, 1f, 0, 0,
                               reader.GetPageSizeWithRotation(currentPageIndex).Height);
                        }
                        else
                        {
                            content.AddTemplate(importedPage, 1f, 0, 0, 1f, 0, 0);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                throw new Exception("There has an unexpected exception" +
                      " occured during the pdf merging process.", exception);
            }
            finally
            {
                document.Close();
            }
            return output.GetBuffer();
        }

        /// <summary>
        /// To add the javascript to be performed for Printing on Load.
        /// </summary>
        /// <param name="SorceFilePath"></param>
        /// <param name="DestinationPDFFilePath"></param>
        void AttachPrintScript(String SorceFilePath, String DestinationPDFFilePath)
        {
            var doc = new Document();
            var reader = new PdfReader(SorceFilePath);
            using (var memoryStream = new MemoryStream())
            {
                var writer = PdfWriter.GetInstance(doc, memoryStream);
                doc.Open();
                // this action leads directly to printer dialogue     
                var jAction = PdfAction.JavaScript("this.print(true);\r", writer);
                writer.AddJavaScript(jAction);
                doc.AddDocListener(writer);
                var cb = writer.DirectContent;
                for (var p = 1; p <= reader.NumberOfPages; p++)
                {
                    doc.SetPageSize(reader.GetPageSize(p));
                    doc.NewPage();
                    var page = writer.GetImportedPage(reader, p);
                    var rot = reader.GetPageRotation(p);
                    if (rot == 90 || rot == 270)
                        cb.AddTemplate(page, 0, -1.0F, 1.0F, 0, 0, reader.GetPageSizeWithRotation(p).Height);
                    else
                        cb.AddTemplate(page, 1.0F, 0, 0, 1.0F, 0, 0);
                }
                reader.Close();
                doc.Close();
                File.WriteAllBytes(DestinationPDFFilePath, memoryStream.ToArray());
            }
        }
    }

    /// <summary>
    /// Implements custom page events.
    /// </summary>
    internal class PdfPageEvents : IPdfPageEvent
    {
        #region members
        private BaseFont _baseFont = null;
        private PdfContentByte _content;
        #endregion

        #region IPdfPageEvent Members
        public void OnOpenDocument(PdfWriter writer, Document document)
        {
            _baseFont = BaseFont.CreateFont(BaseFont.HELVETICA,
                             BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
            _content = writer.DirectContent;
        }

        public void OnStartPage(PdfWriter writer, Document document)
        {
        }

        public void OnEndPage(PdfWriter writer, Document document)
        {
            // Write header text
            string headerText = String.Empty;//"PDF Merger by Smart-Soft";
            _content.BeginText();
            _content.SetFontAndSize(_baseFont, 8);
            _content.SetTextMatrix(GetCenterTextPosition(headerText,
                                   writer), writer.PageSize.Height - 10);
            _content.ShowText(headerText);
            _content.EndText();

            // Write footer text (page numbers)
            string text = "Page " + writer.PageNumber;
            _content.BeginText();
            _content.SetFontAndSize(_baseFont, 8);
            _content.SetTextMatrix(GetCenterTextPosition(text, writer), 10);
            _content.ShowText(text);
            _content.EndText();
        }

        public void OnCloseDocument(PdfWriter writer, Document document)
        {
        }

        public void OnParagraph(PdfWriter writer,
                    Document document, float paragraphPosition)
        {
        }

        public void OnParagraphEnd(PdfWriter writer,
                    Document document, float paragraphPosition)
        {
        }

        public void OnChapter(PdfWriter writer, Document document,
                              float paragraphPosition, Paragraph title)
        {
        }

        public void OnChapterEnd(PdfWriter writer,
                    Document document, float paragraphPosition)
        {
        }

        public void OnSection(PdfWriter writer, Document document,
                    float paragraphPosition, int depth, Paragraph title)
        {
        }

        public void OnSectionEnd(PdfWriter writer,
                    Document document, float paragraphPosition)
        {
        }

        public void OnGenericTag(PdfWriter writer, Document document,
                                 Rectangle rect, string text)
        {
        }
        #endregion

        private float GetCenterTextPosition(string text, PdfWriter writer)
        {
            return writer.PageSize.Width / 2 - _baseFont.GetWidthPoint(text, 8) / 2;
        }
    }
}
